require 'rubygems'
require 'sqlite3'

#require 'config.rb'

require 'TalkCommand'
require 'TalkLeaning'
require 'TalkSupport'
require 'TalkOmake'

class TalkClass

	def initialize(my_data={},options={},csv_files={},db_file_name='talk.db')
		@my=my_data
		@option=options

		#返事を入れておく配列
		@responses=Array.new
		srand(Time.now.to_i)
		if(FileTest.exists?(db_file_name)) then
			@talkdb = SQLite3::Database.new(db_file_name)
		else
			@talkdb = SQLite3::Database.new(db_file_name)
			create_tables
			load_csv_files(csv_files) if csv_files.size!=0
		end
		p @my
	end

	#返事を詰め込む
	def add_response(response)
		return false if response==nil
		@responses.push(response)
		return true
	end

	#返事の格納された配列を返す
	def responses
		return @responses
	end

	#返事配列を初期化
	def reflesh
		@responses=Array.new
	end

	#メッセージを分類する。
	#引数なしもしくはtypeが空だと独り言を考える
	def parse(type='',from_name='',tweet='',id='',time='')
		#puts "[DEBUG:parse] #{type} #{from_name} #{tweet}"
		reply_message=nil

		#とりあえず、短縮URLを元に戻す。
		tweet = replace_uri(tweet,'expand')

		case type
		when 'DM'
			reply_message=think_message(from_name)
		when 'TW'
			if (/@#{@my['name']}/ =~ tweet or /^#{@my['call']}(さん|ちゃん|\S*)へ(、|。|\s)/ =~ tweet) then #自分宛のツィート
				puts "#{from_name}から話しかけられました"
				reply_message = think_answer(from_name,tweet,'reply') #返事をする
			else #それ以外
				puts "#{from_name}がなにか言ってます"
				if (/^@(.*) / =~ tweet) then #他人宛なら無視
					puts "#{$1}宛でした。。。"
					return nil
				end
				reply_message = think_answer(from_name,tweet,'say') #話しかける
			end
		else #自分から話しかける
			reply_message = think_tweet
		end

		puts "--- [#{tweet}]"

		if (reply_message!=nil  and reply_message['message']!=nil) then
			#メッセージ中のURLを短縮
			reply_message['message'] = replace_uri(reply_message['message'])
			#長文を分割したり、省略したりする
			splited_messages = split_message(reply_message['message'])
			reply_message.store('messages',splited_messages)
		end
		reply_message.store('id',id) if reply_message!=nil
		add_response(reply_message)
		return reply_message
	end

	#DMへの返事
	def think_message(from_name='')
		message="@#{@my['admin']} #{from_name}さんからお手紙もらったよ！||お手紙ありがとう！後で返事書くからね"
		return {'to'=>from_name,'message'=>message,'mode'=>'send','order'=>''}
	end
	
	#誰かから話しかけられたときの返事
	def think_answer(from_name='',tweet='',mode='')
		return nil if (from_name=='' or tweet=='')
		message=''
		answer=''

		#自分宛のアレを消す
		tweet.gsub!("@#{@my['name']} ","")

		#特定のツィートには特別な返事をするよ
		result = special(tweet,mode,from_name)
		if (result!=nil and result['message']!='') then
			result['message'] = "#{result['message']} RT #{tweet}"
			return {'to'=>from_name,'message'=>result['message'],'order'=>result['order'],'mode'=>mode}
		end

		return nil if (from_name==@my['name'])#以下、自分からのメッセージは無視

		#(1) 区切り文字で文節に分割
		phrase = tweet.split(/[,.!?、。！？\s\n]/)
		phrase.delete("")
		
		#(2)文節ごとに返答を考える
		phrase.each{|str|
			choices = search_choices(str,true) if (mode=='reply') #返事をする
			choices = search_choices(str,false) if (mode=='say') #話しかける
			message+=choices[rand(choices.size)] if(choices!=nil)
		}
		answer_tmp = replace(message,from_name) #テンプレ対応
		answer = command(answer_tmp) #コマンド対応
		return {'to'=>from_name,'message'=>answer,'order'=>'','mode'=>mode} if(answer!='')
		return nil
	end

	#独り言をしゃべる
	def think_tweet(nowH=0,nowM=0)
		order=''
		#(1)現在時刻を調べます、ただし10分くぎりです。
		nowH = Time.now.strftime("%H").to_i if(nowH==0)
		nowM = Time.now.strftime("%M").to_i if(nowM==0)
		nowM = (nowM/10)*10 #10分区切りではかります。
		time = nowH*100+nowM
		time_name = ''

		#(2)時間帯を判定
		case time
		when 600 .. 1200
			time_name = 'morning'
		when 1430 .. 1530
			time_name = 'teaTime'
		when 1200 .. 1700
			time_name = 'afterNoon'
		when 1700 .. 2000
			time_name = 'evening'
		else
			time_name = 'night'
		end

		#(3)テーブルから引いてくる
		result=nil
		sql = "select message from speak where time=='every' or time=='#{time_name}' or time=='#{time}';"
		begin
			result = @talkdb.execute(sql);
		rescue SQLite3::SQLException
			error_time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{error_time}\t[ERROR:think_tweet] database access error"
		end
		result.flatten! if(result!=nil)

		#選択肢の中から適当に１つ選ぶ
		message =  result[rand(result.size)]

		if (rand(3)==1) then #たまに友人に話しかける
			forFriendMesage = for_special_friend
			message = "#{message}||#{forFriendMesage}"  if forFriendMesage!=''
		end

		message_tmp = replace(message)#テンプレ対応
		response = {'message'=>command(message_tmp),'order'=>order,'mode'=>'say','to'=>'ALL'}#コマンド対応
		return response
	end

	#1)単語が言い換えテーブルにあるか調べる
	#2)あったら返事テーブルを調べる
	#3)返事の種類を配列で返す
	def search_choices(str,personal_mode=true)
		#puts "search_choices #{str}"
		result=nil
		begin
			new_key = @talkdb.execute("select value from trans where key=='#{str}';")
			new_key.flatten! if(new_key!=nil)
			if (personal_mode) then
				choices = @talkdb.execute("select say from reply where get=='#{new_key[0]}';")
			else
				choices = @talkdb.execute("select say from reply where get=='#{new_key[0]}' and flag=='SAY_TO_US';")
			end
			if (choices!=nil) then
				choices.flatten!
				result = choices[0].split("|") if (choices[0]!=nil)
			end
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:search_choices] database access error"
		end
		return result
	end

	#あらかじめ設定されている文字列を置き換え
	def replace(str,from_name='')
		source = str.scan(/%[a-zA-Z0-9]*_[a-zA-Z0-9]*%/)
		source.each{|command|
			keys = command.gsub("%",'').split('_')
			if (keys[0] == 'user') then
				keys[0] = from_name
			end
			result = @talkdb.execute("select value from personal where name=='#{keys[0]}' and key=='#{keys[1]}';")
			result.flatten! if(result!=nil)
			str.sub!(command,result[0]) if(result[0]!=nil)
			str.sub!(command,from_name) if(result[0]==nil and keys[1]=='name')
		}
		return str
	end

	def pub_command(str='')
		return command(str) if(str!='')
	end

	#特別な対応を考えます
	def special(message='',mode='',from_name='')
		answer=''

		#自分から自分へのなんか
		#遅延調査とか

		answer = for_special_friend(message,from_name)
		return {'message'=>answer,'order'=>''} if(answer!='')

		return nil if (from_name==@my['name'])#以下、自分からのメッセージは無視

		#Twitter Order
		case message
		when %r((follow|フォロー)して),%r((友達|友人)になって)
			return {'message'=>"OK、これからよろしく！",'order'=>'follow'} if(mode=='reply')
		when %r((remove|リムーブ|unfollow|アンフォロー)して)
			return {'message'=>'そう？ちょっとまってね。。。','order'=>'unfollow'} if(mode=='reply')
		when %r((^\[RT\]|^\[拡散希望\]|【拡散希望】))
			return {'message'=>'OK！協力するよ！','order'=>'retweet'}
		end
		
		#外部サービス
		case message
		#診断メーカをやってる人がいたら自分もやる
		when %r(http://shindanmaker.com/(\d+))
			id = $1.to_i
			answer = get_shindan_maker(id,@my['name'])
			return {'message'=>answer,'order'=>''} if(answer!='')
		else #自分ではわからないので、外部に協力をあおぎます。
			answer = ILL(message,from_name) if(mode=='reply')
			return {'message'=>answer,'order'=>''} if(answer!='')
		end

		

		#以降、RTより後ろは削除
		rtindex = message.index("RT")
		message = message[0..rtindex] if(rtindex!=nil)

		#学習成果を教えてあげる
		case message
		when %r(「(.*)」て(何|どういう意味))
			str=$1
			result = search_dict(str)
			result.flatten!
			answer = "#{str}は「#{result[0]}」てゆう意味だよ！" if(result.size>0)
			if (answer!='') then
				return {'message'=>answer,'order'=>''}
			else
				return {'message'=>"う〜ん、なんだろう？",'order'=>''}
			end
		when %r(「(.*)」の仲間)
			str=$1
			result = search_dict(str,'updown')
			result.flatten!
			answer = "#{str}の仲間は#{result[rand(result.size)]}とかだよ〜"
			if (answer!='') then
				return {'message'=>answer,'order'=>''}
			else
				return {'message'=>"ごめんね、わからないの、、、おしえて？\n[「xxx」は「ooo」の仲間]って言ってくれると覚えるよ",'order'=>''}
			end
		end

		#学習
		learn_data = learn(message)
		return nil if(learn_data==nil)
		learn_data.each{|data|
			case data['table']
			when 'speak' #独り言だけは管理人の言う事しか学習しない
				if(from_name==@my['admin']) then
					res = append_speak(data['time'],data['message'])
					answer = "ありがとう！" if(res!=nil)
					return {'message'=>answer,'order'=>''} if(answer!='')
				end
			when 'reply'
				res = append_reply(data['key'],data['value'])
				answer = "わかった！" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			when 'trans'
				res = append_trans(data['key'],data['value'])
				answer = "覚えたよ！" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			when 'dict'
				res = append_dict(data['key'],data['value'],data['type'])
				answer = "そーなのかー" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			end
		}
		return nil
	end

	def close
		@talkdb.close
	end

##データベース　はじめ
	#初期設定のファイルを読み込む
	def load_csv_files(csv_files)
		load_file('trans',csv_files['trans_data_file'])
		load_file('reply',csv_files['reply_data_file'])
		load_file('personal',csv_files['personal_data_file'])
		load_file('speak',csv_files['speak_data_file'])
		load_file('dict',csv_files['dict_data_file'])
	end

	#CSVファイルを読み込んでそれぞれのデータベースに登録する
	def load_file(mode,file_name)
		if (file_name!=nil and FileTest.exists?(file_name)) then
			file = open(file_name)
		else
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:loading_files] #{file_name} is not exist"
		end
		file.each {|line|
			datas = line.split(',')
			case mode
			when 'reply'
				append_reply(datas[0],datas[1],datas[2]) if(datas[0]!=nil and datas[1]!=nil and datas[2]!=nil)
			when 'trans'
				append_trans(datas[0],datas[1]) if(datas[0]!=nil and datas[1]!=nil)
			when 'personal'
				append_personal(datas[0],datas[1],datas[2]) if(datas[0]!=nil and datas[1]!=nil and datas[2]!=nil)
			when 'speak'
				append_speak(datas[0],datas[1]) if(datas[0]!=nil and datas[1]!=nil)
			when 'dict'
				append_dict(datas[0],datas[1],datas[2]) if(datas[0]!=nil and datas[1]!=nil and datas[2]!=nil)
			end
		}
		file.close
	end

	#replyテーブルへの追加
	def append_reply(get='',say='',flag='')
		return nil if (get==''or say=='')
		begin
			nowdata = @talkdb.execute("select get,say from reply where get='#{get}'")
			
			if(nowdata.size==0) then
				sql ='insert into reply values (:get,:say,:flag);'
				#まだ登録されてないなら
				if(flag!='') then
					result = @talkdb.execute(sql,:get=>get,:say=>say,:flag=>flag.chomp) 
				else
					result = @talkdb.execute(sql,:get=>get,:say=>say,:flag=>'SAY_TO_US')
				end
				result = append_trans(get,get)
			else
				if (nowdata[0][1] != say) then
					newdata = "#{nowdata[0][1]}|#{say}"
					sql ="update reply set say='#{newdata}' where get='#{get}';"
					result = @talkdb.execute(sql)
				end
			end
			return result
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_reply] database access error"
		end
		return nil
	end
	#personalテ−ブルへの追加
	def append_personal(name='',key='',value='')
		return nil if(name=='' or key=='' or value=='')
		
		sql ='insert into personal values (:id,:name,:key,:value);'
		begin
			return @talkdb.execute(sql,:name=>name,:key=>key,:value=>value.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_personal] database access error"
		end
		return nil
	end
	#transテ−ブルへの追加
	def append_trans(key='',value='')
		return nil if(key=='' or value=='')
		sql ='insert into trans values (:key,:value);'
		begin
			return @talkdb.execute(sql,:key=>key,:value=>value.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_trans] database access error"
		end
		return nil
	end
	#speakテ−ブルへの追加
	def append_speak(time='',message='')
		return nil if(time=='' or message=='')
		sql ='insert into speak values (:id,:time,:message);'
		begin
			return @talkdb.execute(sql,:time=>time,:message=>message.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_speak] database access error"
		end
		return nil
	end
	#dictテ−ブルへの追加
	def append_dict(key='',value='',type='')
		return nil if(type=='' or key=='' or value=='')
		sql ='insert into dict values (:key,:value,:type);'
		begin
			return @talkdb.execute(sql,:key=>key,:value=>value,:type=>type.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_dict] database access error"
		end
		return nil
	end
	#dictテーブルを検索
	def search_dict(key='',type='mean')
		return nil if(key=='')
		begin
			return @talkdb.execute("select value from dict where key='#{key}' and type='#{type}'")
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:search_dict] database access error"
		end
		return nil
	end

	def create_tables
		begin
			#reply table
			#getを受け取ったときにsayと返す
			#flagで返す相手を限定
			## SAY_TO_MEなら自分宛のときだけ
			## SAY_TO_USなら限定なし
			sql ='create table reply ('
				sql+='get text not null primary key'
				sql+=',say text not null'
				sql+=',flag text not null' #SAY_TO_ME or SAY_TO_US
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into reply values (:get,:say,:flag);'
			@talkdb.execute(sql,:get=>'こんにちは',:say=>'こんにちは！|こんちわ！',:flag=>'SAY_TO_US')
			@talkdb.execute(sql,:get=>'好きな食べ物は',:say=>'%my-likeFood%です。',:flag=>'SAY_TO_ME')

			#transe table
			#keyという単語とvalueという単語を変換する
			#valueはreplyテーブルに登録されているもの
			sql ='create table trans ('
				sql+='key text not null primary key'
				sql+=',value text not null'
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into trans values (:key,:value);'
			@talkdb.execute(sql,:key=>'好きな食べ物は',:value=>'好きな食べ物は')
			@talkdb.execute(sql,:key=>'こんにちは',:value=>'こんにちは')
			@talkdb.execute(sql,:key=>'こんちわ',:value=>'こんにちは')
			@talkdb.execute(sql,:key=>'Hello',:value=>'こんにちは')
			@talkdb.execute(sql,:key=>'Hi',:value=>'こんにちは')

			#personal table
			#ユーザの個人情報を保存
			#nameはユーザのスクリーン名
			#keyのときにvalue
			sql ='create table personal ('
				sql+='id integer primary key'
				sql+=',name text not null'
				sql+=',key text not null'
				sql+=',value text not null'
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into personal values (:id,:name,:key,:value);'
			@talkdb.execute(sql,:name=>'my',:key=>'name',:value=>@my['name'])
			@talkdb.execute(sql,:name=>'my',:key=>'likeFood',:value=>'沖縄そば')
			@talkdb.execute(sql,:name=>'testUser',:key=>'name',:value=>'テストなユーザ')

			#speak table
			#timeのときの独り言候補
			#sayとしゃべる
			sql ='create table speak ('
				sql+='id integer primary key'
				sql+=',time text not null' #every/morning/afterNoon/teaTime/evening/night or 24time
				sql+=',message text not null'
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into speak values (:id,:time,:message);'
			@talkdb.execute(sql,:time=>'every',:message=>'<NowTime>をお知らせします。')
			@talkdb.execute(sql,:time=>'2000',:message=>'8時、そろそろおなか空いたかも。')
			@talkdb.execute(sql,:time=>'night',:message=>'夜ですね、わかります。')

			sql ='create table dict ('
				sql+='key text primary key'
				sql+=',value text not null'
				sql+=',type text not null' #updown/mean
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into dict values (:key,:value,:type);'
			@talkdb.execute(sql,:key=>'車',:value=>'リバティ',:type=>'updown')
			@talkdb.execute(sql,:key=>'IT',:value=>'Infomation Technology：情報技術',:type=>'mean')
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:search_dict] failed to create tables"
			return false
		end
		return true
	end

##データベース　おわり

end
